{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Limitation and Pitfalls\n",
    "\n",
    "## Not support in-place array operations\n",
    "\n",
    "In-place array operations lead to confusion in gradient definition and therefore the team decides to exclude the support for all in-place array operations. For example, using the following mutable array operation is not allowed in MinPy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Array' object has no attribute 'transpose'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-c6777f33a28a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mminpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtranspose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'Array' object has no attribute 'transpose'"
     ]
    }
   ],
   "source": [
    "import minpy.numpy as np\n",
    "a = np.zeros((2,3))\n",
    "a.transpose()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But you can use immutable operation instead:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = np.transpose(a)\n",
    "# instead of a.transpose(), which is feasible in NumPy.\n",
    "# In MinPy, it will occur an error, since we can't calculate\n",
    "# its gradient."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A more common example which is not supported is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a[0, 1] = 12"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The system will still allow you to perform such operations, but keep in mind that the autograd will fail in such cases."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Use MinPy consistantly\n",
    "\n",
    "If you try to put NumPy array into MinPy operation, there are some cases that the computation will still happen in NumPy’s namespace instead of MinPy’s. For example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import minpy.numpy as np\n",
    "def simple_add(a, b):\n",
    "    return a + b\n",
    "    \n",
    "# Now we declare two NumPy arrays:\n",
    "import numpy as npp\n",
    "a = npp.ones((10, 10))\n",
    "b = npp.zeros((10, 10))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we pass `a` and `b` into function `simple_add`. the add operation will happen in NumPy’s namespace. This is not the expected behavior. So we recommend you to use MinPy array consistently.\n",
    "\n",
    "On the other hand, if you want to recover NumPy array from MinPy array for other packages like `matplotlib`, you can use `asnumpy`, which will return the corresponding NumPy array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'minpy.array.Array'>\n",
      "<type 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "a = np.zeros((2,3))\n",
    "print(type(a)) # this is a MinPy array\n",
    "print(type(a.asnumpy())) # convert to NumPy array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Not support all submodules\n",
    "\n",
    "Since NumPy package is distributed as multiple submodules, currently not all submodules are supported. If you find any submodules (such as `numpy.random`) without support, please raise an issue on GitHub. The dev team will add support as soon as possible.\n",
    "\n",
    "## Not support multiple executions of the same MXNet symbol before BP\n",
    "\n",
    "Unlike MinPy's primitives, MXNet symbol has internal stage to record gradient information. Thus applying same symbol to different data will fail BP in the later stage. You can create duplicate symbol to fulfil the same goal and designate same parameter name for parameter sharing."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [Root]",
   "language": "python",
   "name": "Python [Root]"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
